using UnityEngine;

namespace GameToolkit.BehaviourTree
{

    [System.Serializable]
    [CompositeTitle("并行任务")]
    [CompositeCategory]
    [CompositeIcon("ce7ad0aeb7a5f1a45817ed5567368cf7")]
    public class Parallel : ExecutableComposite
    {
        enum ELoopType
        {
            LoopOnce,
            AlwaysLoop,
        }

        enum ELoopResult
        {
            MainTask,
            AllSuccess,
            AnySuccess,
            AllComplete,
        }

        [SerializeField]
        ELoopType m_MainLoopType;

        [SerializeField]
        ELoopType m_ParallelLoopType;

        [SerializeField]
        ELoopResult m_ResultFrom;

        public override string GetDescription()
        {
            switch (m_ResultFrom)
            {
                case ELoopResult.MainTask:
                    return $"主任务+并行支线任务";
                case ELoopResult.AllSuccess:
                    return "所有任务执行成功";
                case ELoopResult.AnySuccess:
                    return "任何一个任务执行成功";
                case ELoopResult.AllComplete:
                    return "完成所有任务";
                default:
                    return null;
            }
        }

        public override BehaviourTreeObject Create()
        {
            return new Impl();
        }

        class Impl : SubExecutableRoot, IBehaviourTreeContext
        {
            BehaviourTreeLooper[] mLoopers;
            Parallel mCfg;
            //bool mResetStates;

            public int LoopersCount => mLoopers == null ? 0 : mLoopers.Length;

            public BehaviourTreeLooper GetLooper(int index)
            {
                return mLoopers[index];
            }

            protected override void OnDestroy(BehaviourTreePlayer player)
            {
            }

            protected override bool IsExecutable(BehaviourTreePlayer player)
            {
                return mLoopers.Length > 0;
            }

            protected override void OnCreate(BehaviourTreePlayer player)
            {
                mCfg = composite as Parallel;
                mLoopers = new BehaviourTreeLooper[ChildCount];
                for (int i = 0; i < mLoopers.Length; i++)
                {
                    var looper = player.CreateLooper(GetChild(i));
                    mLoopers[i] = looper;
                }
            }

            protected override NodeState OnInterrupt(BehaviourTreePlayer player, bool successInterruption)
            {
                //for (int i = 0; i < mLoopers.Length; i++)
                //{
                //    mLoopers[i].Interrupt(false, successInterruption);
                //}
                var result = GetResultState();
                return result;
            }

            protected override void OnStart(BehaviourTreePlayer player)
            {
                for (int i = 0; i < mLoopers.Length; i++)
                {
                    mLoopers[i].Interrupt(true, false);
                }
            }

            protected override void OnStop(BehaviourTreePlayer player)
            {
                for (int i = 0; i < mLoopers.Length; i++)
                {
                    mLoopers[i].Interrupt(false, State == NodeState.Success);
                }
            }

            protected override NodeState OnUpdate(BehaviourTreePlayer player)
            {
                if (mCfg.m_MainLoopType == ELoopType.AlwaysLoop || mLoopers[0].State <= NodeState.Running)
                {
                    mLoopers[0].UpdateBehaviour();
                }
                for (int i = 1; i < mLoopers.Length; i++)
                {
                    var looper = mLoopers[i];
                    if (mCfg.m_ParallelLoopType == ELoopType.AlwaysLoop || looper.State <= NodeState.Running)
                    {
                        mLoopers[i].UpdateBehaviour();
                    }
                }
                return GetResultState();
            }

            NodeState GetResultState()
            {
                // get result
                if (mCfg.m_ResultFrom == ELoopResult.MainTask)
                {
                    return mLoopers[0].State;
                }
                else if (mCfg.m_ResultFrom == ELoopResult.AllSuccess)
                {
                    bool run = false;
                    for (int i = 0; i < mLoopers.Length; i++)
                    {
                        var looper = mLoopers[i];
                        if (looper.State == NodeState.Failed)
                            return NodeState.Failed;
                        else if (!run && looper.State <= NodeState.Running)
                            run = true;
                    }
                    return run ? NodeState.Running : NodeState.Success;
                }
                else if (mCfg.m_ResultFrom == ELoopResult.AnySuccess)
                {
                    bool run = false;
                    for (int i = 0; i < mLoopers.Length; i++)
                    {
                        var looper = mLoopers[i];
                        if (looper.State == NodeState.Success)
                            return NodeState.Success;
                        else if (!run && looper.State <= NodeState.Running)
                            run = true;
                    }
                    return run ? NodeState.Running : NodeState.Failed;
                }
                else
                {
                    for (int i = 0; i < mLoopers.Length; i++)
                    {
                        if (mLoopers[i].State <= NodeState.Running)
                            return NodeState.Running;
                    }
                    return NodeState.Success;
                }
            }

        }
    }

}
